package com.tianji.learning.service.impl;


import cn.hutool.db.DbRuntimeException;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.api.dto.leanring.LearningRecordFormDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author huanghui
 * @since 2023-07-21
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    private final ILearningLessonService lessonService;
    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandler taskHandler;
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {

        //1.获取当前用户id
        Long userId = UserContext.getUser();
        //2.查询课表
        LearningLesson lesson =  lessonService.queryByUserIdAndCourseId(userId,courseId);
        if (lesson==null){
            return null;
        }
        //3.查询学习记录 select * from ** where lesson_id =#{lesson_id}
        List<LearningRecord> recordList = lambdaQuery()
                .eq(LearningRecord::getLessonId, lesson.getId())
                .list();
        //4.封装结果
        LearningLessonDTO lessonDTO = new LearningLessonDTO();
        lessonDTO.setId(courseId);
        lessonDTO.setLatestSectionId(lessonDTO.getLatestSectionId());
        lessonDTO.setRecords(BeanUtils.copyList(recordList, LearningRecordDTO.class));
        return lessonDTO ;
    }

    @Override
    @Transactional
    public void addLearningRecord(LearningRecordFormDTO recordDTO) {

        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.处理学习记录
        boolean finished;
        if (SectionType.VIDEO.getValue()  == recordDTO.getSectionType()){
            //2.1处理视频
            finished=handlerVideoRecord(userId,recordDTO);
        }else {
            //2.2处理学习记录
            finished=handlerExamRecord(userId,recordDTO);
        }
        if (!finished) {
            return;
        }
        //3.处理课表数据
        handlerLearningLessonsChanges(recordDTO);
    }

    private void handlerLearningLessonsChanges(LearningRecordFormDTO recordDTO) {
        //1.查询课表
        LearningLesson lesson = lessonService.getById(recordDTO.getLessonId());
        if (lesson == null) {
            throw new BizIllegalException("课程不存在，无法更新数据");
        }

        //2.判断是否有新的完成小节
        boolean allLearned=false;

            //3.如果有新的完成小节，则需要查询课程数据
            CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            if (cInfo == null) {
                throw new BizIllegalException("课程不存在，无法更新数据");
            }
            //4.比较课程是否全部学完，已经学习小节>=课程总小节
            allLearned = lesson.getLearnedSections() + 1 >= cInfo.getSectionNum();



        //5.更新课表
        lessonService.lambdaUpdate()
                .set(lesson.getLearnedSections()==0,LearningLesson::getStatus, LessonStatus.LEARNING.getValue()) //
                .set(allLearned,LearningLesson::getStatus, LessonStatus.FINISHED.getValue())
                .setSql("learned_sections=learned_sections + 1")
                .eq(LearningLesson::getId,lesson.getId())
                .update();
    }

    private boolean handlerExamRecord(Long userId, LearningRecordFormDTO recordDTO) {
        //dto转换为po
        LearningRecord record = BeanUtils.copyBean(recordDTO, LearningRecord.class);
        //填充属性值
        record.setId(userId);
        record.setFinished(true);
        record.setFinishTime(recordDTO.getCommitTime());
        //写入数据库
        boolean success  = save(record);
        if (!success){
            throw new DbRuntimeException("新增考试记录失败！ ");
        }else {
            return true;
        }
    }

    private boolean handlerVideoRecord(Long userId, LearningRecordFormDTO recordDTO) {
        //获取旧课程信息
        LearningRecord old = queryOldRecord(recordDTO.getLessonId(),recordDTO.getSectionId());

        //2.判断是否存在
        if(old==null){
            //3.不存在，则新增学习记录
            //3.1转换po
            LearningRecord record = BeanUtils.copyBean(recordDTO, LearningRecord.class);
            //3.2数据缺失填充
            record.setUserId(userId);
            //3.3写入数据
            boolean success = this.save(record);
            if (!success){
                throw new DbRuntimeException("新增课程记录失败！ ");
            }else {
                return false;
            }
        }
        //4.存在则更新学习记录
        //4.1判断是否是第一次学完
        boolean finished = !old.getFinished() && recordDTO.getMoment() * 2 >= recordDTO.getDuration();   //当前学习进度的两倍，必须大于总时长数并且不是已经完成了的

        if(!finished){
            LearningRecord record = new LearningRecord();
            record.setLessonId(recordDTO.getLessonId());
            record.setSectionId(recordDTO.getSectionId());
            record.setMoment(recordDTO.getMoment());
            record.setId(old.getId());
            record.setFinished(old.getFinished());
            taskHandler.addLearningRecordTask(record);
            return false;
        }

        //4.2.更新记录
        boolean success = lambdaUpdate()
                .set(LearningRecord::getMoment, recordDTO.getMoment())
                .set(LearningRecord::getFinished, true)
                .set( LearningRecord::getUpdateTime, recordDTO.getCommitTime())
                .eq(LearningRecord::getId, old.getId())
                .update();
        if (!success){
            throw new DbRuntimeException("更新学习记录失败！ ");
        }
        //清理缓存
        taskHandler.cleanRecordCache(recordDTO.getLessonId(),recordDTO.getSectionId());
        return  true ;
    }

    private LearningRecord queryOldRecord(Long lessonId,Long sectionId) {
        //1.优先查询缓存
        LearningRecord record = taskHandler.readRecordCache(lessonId, sectionId);
        //2.如果命中，直接放回
        if (record != null) {
            return record;
        }
        //3.未命中，查询数据库
        record = lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        //4.写入缓存
        taskHandler.writeRecordCache(record);
        return record;
    }




}
